///////////////////////////////////////////////////////////
// 
//  Player.cpp
//
//  Wiicussion
//  HCI 575 Class project
//  Spring 2007
// 
//  Authors:  Jeremy Bennett
//            Adam Faeth
//            Michael Oren
//
///////////////////////////////////////////////////////////

// Local Includes
#include "stdafx.h"
#include "Player.h"
#include "MyContext.h"
#include "MyImage.h"

// SDL Includes
#include <SDL_opengl.h>

// System Includes
#include <stdio.h>
#include <iostream>
#include <algorithm>
#include <math.h>

#ifdef __APPLE_CC__
  #define UINT8 unsigned char
#endif

float s_SCREEN_WIDTH  = 1440.0f;
float s_SCREEN_HEIGHT = 900.0f;

bool Player::s_bVerbose = false;

Player::Player()
: _uID(),
  _instrument(),
  _fInstrWnd(),
  _iInstrRange(),
  _horseScore(5),
  _bActive(false),
  _bActiveGamePlayer(false),
#if defined(USE_GLOVEPIE)
  // Deprecated:
  _pJoystick(),
  _bButtonArr(),
  _bButtonArr2(),
#else
  _pMote(),
#endif
  _fUISize(),
  _fUIPos(),
  _fColor(),
  _fPoint(),
  _fLocation(),
  _fDirection(),
  _bNote(),
  _fAccel(),
  _cBuffer(),
  _rumbleCount(0)
{
    // Initialize the default instruments
    _instrument[0] = 0;
    _instrument[0] = 3;

    // Initialize the default player color
    _fColor[0] = 0.0f;
    _fColor[1] = 0.0f;
    _fColor[2] = 1.0f;
    _fColor[3] = 0.0f;

    // 

#if defined(USE_GLOVEPIE)
    // Initialize the player buttons
	for(int i = 0; i<=11; i++)
		_bButtonArr[i] = false;
#endif
}

Player::~Player()
{
}

bool 
Player::toggleActive() 
{
    _bActive = !_bActive;
    return true;
}


bool 
Player::setUIPosition( float x, float y, float w, float h )
{
    _fUIPos[0] = x;
    _fUIPos[1] = y;
    _fUISize[0] = w;
    _fUISize[1] = h;
    return true;
}



bool 
Player::setRendPosition( const float *pPos )
{
    _fUIPos[0] = pPos[0];
    _fUIPos[1] = pPos[1];
    return true;
}

bool 
Player::calibrateInstuments( float x, float y, float w, float h, float s, float e )
{
    _fInstrWnd[0] = x;
    _fInstrWnd[1] = y;
    _fInstrWnd[2] = w;
    _fInstrWnd[3] = h;
    _iInstrRange[0] = s;
    _iInstrRange[1] = e;

    return true;
}

#define ObtainAxis( val, axis, off, max_val, min_size, max_size )  \
{                                                                  \
    val = (((float)SDL_JoystickGetAxis(_pJoystick[0], axis))+off); \
	val *= max_size;                                               \
	val /= max_val;                                                \
	if ( val < min_size )        val = min_size;                   \
	else if ( val > (max_size) ) val = max_size;                   \
}

bool 
Player::preFrame()
{
#if defined(USE_GLOVEPIE)
    // DEPRECATED:

    // Early out if no joystick or inactive
    if (!_pJoystick) 
    { return true; }

    // TOXIC: Create enumerations for the buttons
    UINT8 bIR1 = SDL_JoystickGetButton(_pJoystick[0], 12 ),
          bIR2 = SDL_JoystickGetButton(_pJoystick[0], 13 ),
          bIR3 = SDL_JoystickGetButton(_pJoystick[0], 14 ),
          bIR4 = SDL_JoystickGetButton(_pJoystick[0], 15 );
    
    float x0=0.0f, y0=0.0f;
    
    if ( bIR1 && bIR2 && bIR3 && bIR4 ) {
        // Only calculate position if all 4 lights are detected
        float fX1 = (float)SDL_JoystickGetAxis(_pJoystick[0], 0),
              fY1 = (float)SDL_JoystickGetAxis(_pJoystick[0], 1),
              fX2 = (float)SDL_JoystickGetAxis(_pJoystick[0], 2),
              fY2 = (float)SDL_JoystickGetAxis(_pJoystick[0], 3),
              fX3 = (float)SDL_JoystickGetAxis(_pJoystick[0], 4),
              fY3 = (float)SDL_JoystickGetAxis(_pJoystick[0], 5),
              fX4 = (float)SDL_JoystickGetAxis(_pJoystick[0], 6),
              fY4 = (float)SDL_JoystickGetAxis(_pJoystick[0], 7);

        std::cout << " IR1: (" << fX1 << "," << fY1 << ")"
                  << " IR2: (" << fX2 << "," << fY2 << ")"
                  << " IR3: (" << fX3 << "," << fY3 << ")"
                  << " IR4: (" << fX4 << "," << fY4 << ")" << std::endl;

    } else if ( bIR1 || bIR2 || bIR3 || bIR4 ) {
        // Set position base upon the available IRs
        float fX1=0.0f,
              fY1=0.0f,
              fX2=0.0f, 
              fY2=0.0f,
              fX3=0.0f,
              fY3=0.0f,
              fX4=0.0f,    
              fY4=0.0f;
            
        if ( bIR1 ) {
              fX1 = (float)SDL_JoystickGetAxis(_pJoystick[0],0);
              fY1 = (float)SDL_JoystickGetAxis(_pJoystick[0],1);
        }

        if ( bIR2 ) {
              fX2 = (float)SDL_JoystickGetAxis(_pJoystick[0],2);
              fY2 = (float)SDL_JoystickGetAxis(_pJoystick[0],3);
        }

        if ( bIR3 ) {
              fX3 = (float)SDL_JoystickGetAxis(_pJoystick[0],4);
              fY3 = (float)SDL_JoystickGetAxis(_pJoystick[0],5);
        }

        if ( bIR4 ) {
              fX4 = (float)SDL_JoystickGetAxis(_pJoystick[0],6);
              fY4 = (float)SDL_JoystickGetAxis(_pJoystick[0],7);
        }

        std::cout << " IR1: (" << fX1 << "," << fY1 << ")"
                  << " IR2: (" << fX2 << "," << fY2 << ")"
                  << " IR3: (" << fX3 << "," << fY3 << ")"
                  << " IR4: (" << fX4 << "," << fY4 << ")" << std::endl;

    } else {
        // If no IR lights are detected then set the point position based
        // upon the raw acceleration.
        ObtainAxis( x0, 9, 32768.0f, 65535.0f, 0.0f, s_SCREEN_WIDTH ); // x0-axis
        ObtainAxis( y0, 10, 32768.0f, 65535.0f, 0.0f, s_SCREEN_WIDTH ); // y0-axis
    	
        // Average the current value with the previously stored valued
        // Note: The previous value is weight heavily.
        const float fAvg = 19.0f;
        _fPoint[0] = (_fPoint[0] * (fAvg-1.0f) + x0) / fAvg;
        _fPoint[1] = (_fPoint[1] * (fAvg-1.0f) + y0) / fAvg;
    }
#else
    _updateState(0);
    _updateState(1);
    _updateInstrument(0);
    _updateInstrument(1);
#endif

    if (s_bVerbose) { std::cout << " Pos0: (" << _fPoint[0] << "," << _fPoint[1] << ")" << std::endl; }

    return true;
}

bool 
Player::postFrame()
{
    return true;
}

bool 
Player::renderPointer( MyContext *pContext )
{
    static const float s_ptr_width = 20.0f;

    glPushMatrix();
    glLoadIdentity();
    
    // Setup Rendering Environment
    glPointSize(4.0f);

    glColor4fv(_fColor);

    MyImage *pImage = (MyImage*)pContext->texture(PLAYER_POINTER_TEX);

    pImage->bindTexture();
    pImage->enableTexture();

    pContext->renderRect( _fPoint[0][0]-s_ptr_width, 
                          _fPoint[0][1]-s_ptr_width, 
                          2*s_ptr_width, 2*s_ptr_width );

    pContext->renderRect( _fPoint[1][0]-s_ptr_width, 
                          _fPoint[1][1]-s_ptr_width, 
                          2*s_ptr_width, 2*s_ptr_width );

    pImage->disableTexture();

    glPopMatrix();

    return true;
}

bool 
Player::renderPlayer( MyContext *pContext )
{   
    glPushMatrix();
    glLoadIdentity();

    glTranslatef(_fUIPos[0],_fUIPos[1],0.0f);
    
    float sf_bgColor[]  = { 0.0f, 0.0f, 1.0f };

    // Render the background texture
    MyImage *pImage;

    //_fUISize[0] = 256.0f;

    pImage = (MyImage*)pContext->texture(PLAYER_BACKGROUND_TEX+_bActive);
    pImage->bindTexture();
    pImage->enableTexture();
    pContext->renderRect(0.0f,0.0f,_fUISize[0],_fUISize[1]);
    pImage->disableTexture();

    float off = 128.0f, dist = 29.0f;

    /////
    // Render the Left Instrument

    pImage = (MyImage*)pContext->instrument(_instrument[0]);
    pImage->bindTexture();
    pImage->enableTexture();
    pContext->renderRect(0.0f,0.0f,off,_fUISize[1]);
    pImage->disableTexture();

    /////
    // Render the Right Instrument

    pImage = (MyImage*)pContext->instrument(_instrument[1]);
    pImage->bindTexture();
    pImage->enableTexture();
    pContext->renderRect(_fUISize[0]-off+dist,0.0f,off,_fUISize[1]);
    pImage->disableTexture();

    glPopMatrix();

    // Render the player text strings
    // NOTE: They are offset from where the player UI is being rendered

    // Player
    sprintf( _cBuffer, " Player: %d\0", _uID + 1);
    pContext->renderText( _cBuffer, _fUIPos[0]+93, _fUIPos[1]+95 );

    // Score
    sprintf( _cBuffer, " Score: %d\0", _horseScore );
    pContext->renderText( _cBuffer,  _fUIPos[0]+93, _fUIPos[1]+20 );
 
    return true;
}

bool 
Player::_updateState( int iMote )
{
    
    #if defined(_WIN32)
    if ( _pMote[iMote] ) {
        // Obtain the Normalized IR Data
        _pMote[iMote]->getNormIRData(_fPoint[iMote][0],_fPoint[iMote][1]);
        _fPoint[iMote][0] = 1280.0f - (1280.0f * _fPoint[iMote][0]);
        _fPoint[iMote][1] = 800.0f - (800.0f * _fPoint[iMote][1]);

        // Obtain the Normalized Motion Data
        _pMote[iMote]->getMotionData(_fAccel[iMote][0],_fAccel[iMote][1],_fAccel[iMote][2]);
        if ( _fAccel[iMote][2] < -2.0f ) {
            _bNote[iMote] = true;
			if(!getRumble(iMote)){
				setRumble(iMote, true);
				_rumbleCount = 0;
			}
        } else {
            _bNote[iMote] = false;
			if(getRumble(iMote) && _rumbleCount>=60){
				setRumble(iMote, false);
				_rumbleCount = 0;
			}
			else
				_rumbleCount++;
        }
    }
    #endif
    
    return true;
}

bool 
Player::_updateInstrument( int iMote )
{
    float width = _fInstrWnd[2]/(_iInstrRange[1]-_iInstrRange[0]); 
    float dist  = _fPoint[iMote][0]-_fInstrWnd[0];
	if(!isButtonPressed(iMote,WIIMOTE_BUTTON_B))
		_instrument[iMote] = dist/width;

    return true;
}

#if defined(USE_GLOVEPIE)

// DEPRECATED:

bool 
Player::setJoystick( SDL_Joystick *pJoy1, SDL_Joystick *pJoy2 )
{
    if ( !pJoy1 || !pJoy2 ) return false;

    _pJoystick[0] = pJoy1;
    _pJoystick[1] = pJoy2;
    
    return true;
}

void 
Player::setButton(int iButton, bool pressed){
	_bButtonArr[iButton] = pressed;
}

bool 
Player::getButton(int iButton){
	return _bButtonArr[iButton];
}

void 
Player::setButton2(int iButton, bool pressed){
	_bButtonArr2[iButton] = pressed;
}

bool 
Player::getButton2(int iButton){
	return _bButtonArr2[iButton];
}

#else

bool 
Player::setWiimote( HaptWiimote *pMote1, HaptWiimote *pMote2 )
{
    _pMote[0] = pMote1;
    _pMote[1] = pMote2;

    return true;
}

bool 
Player::isButtonPressed( int iMote, HaptWiimoteButton iButton )
{
    bool res = false;

    if ( iMote >= 0 && iMote < 2 && _pMote[iMote] != NULL) {
        res = _pMote[iMote]->isButtonPressed(iButton);
    }
        
    return res; 
}

#endif